<?php

namespace LRP;

use LRP\Contract\AppInterface;
use LRP\Contract\TubeFactoryInterface;
use LRP\Exception\CommandException;
use LRP\Utils\Sys;

/**
 * Class App
 *
 * PHP Version > 7.0
 *
 * @package LRP
 * @author  Jon
 * @link    https://gitee.com/joncc/long-running-processor
 */
class App implements AppInterface
{
    const FUN_MAIN = 'main';

    private static $tube_factory;
    private static $connection;

    public function run(): void
    {
        $this->start();

        $php = Sys::phpCmd();
        if (empty($php)) {
            throw new CommandException('php no found');
        }

        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
        $file = $trace[0]['file'];

        foreach (Register::getTubes() as $tube) {
            for ($i = 0; $i < Register::getTubeLineNum($tube); $i++) {
                self::execInBg("$php $file $tube");
            }
        }
    }

    /**
     * @param $tube
     */
    public function work($tube)
    {
        $worker = new Worker($tube);
        $worker::createWithFactory(self::$tube_factory);
        $worker->start();
    }

    /**
     * @param string $host
     * @param int $port
     * @param int $connectTimeout
     * @return Contract\TubeInterface
     */
    public static function create(string $host = '127.0.0.1', int $port = 6379, int $connectTimeout = 0)
    {
        self::$tube_factory = new TubeFactory($host, $port, $connectTimeout);
        return self::createWithFactory(self::$tube_factory);
    }

    /**
     * @param TubeFactoryInterface $factory
     * @return Contract\TubeInterface
     */
    public static function createWithFactory(TubeFactoryInterface $factory)
    {
        self::$connection = $factory->create();
        return self::$connection;
    }

    /**
     * @param $cmd
     */
    private static function execInBg($cmd)
    {
        if (Sys::isWin()) {
            $WshShell = new \COM('WScript.Shell');
            $WshShell->Run($cmd, 7, false);
        } else {
            exec("$cmd >/dev/null &");
        }
    }

    private function start()
    {
        Sys::alarm();

        foreach (Register::getTubes() as $tube) {

            $cls = Register::getHandle($tube);

            $result = call_user_func_array([(new $cls), self::FUN_MAIN], []);
            if ($result === TASK::STATUS_OK) {
                continue;
            } elseif ($result instanceof Task) {
                self::$connection->type($tube)->push($result);
            } elseif (is_array($result)) {
                foreach ($result as $one_task) {
                    if ($one_task instanceof Task) {
                        self::$connection->type($tube)->push($one_task);
                    }
                }
            }
        }
    }
}